﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using ResourcesOverMvc.Web.Mvc;
using Samples.WebService.Controllers;

namespace Samples.WebService
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new MultipleRepresentationsAttribute());
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRomRoute(
                "Default_Details", // Route name
                "{controller}/{id}", // URL with parameters
                new { action = "Details" } // Parameter defaults
            );

            routes.MapRomRoute(
                "Default", // Route name
                "{controller}", // URL with parameters
                new { controller = "Home", action = "Index" } // Parameter defaults
            );
        
            // Catch any requests that don't map to a valid route and pass them to the error controller
            routes.MapRomRoute(
                "CatchAll",
                "{*url}",
                new { controller = "Error", action = "Http404" }
            );
        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            
            ModelBinders.Binders.DefaultBinder = (new MultipleRepresentationsBinder());

            // Change from the default parameter used to override POST
            RomHttpRequestWrapper.HttpMethodOverrideQueryStringId = "_method";

            // Change from the default Content Type to use when the client doesn't supply one
            RomHttpRequestWrapper.DefaultContentType = "application/xhtml+xml";

            // Change the defult format managers so we use JSON.Net rather than .Net's default serializer
            // and the XML based handlers don't require an XSLT
            FormatManager.Current.ResponseFormatHandlers.Clear();
            FormatManager.Current.ResponseFormatHandlers.Add(new XhtmlFormatHandler { IgnoreMissingXslt = true });
            FormatManager.Current.ResponseFormatHandlers.Add(new XmlFormatHandler { IgnoreMissingXslt = true });
            FormatManager.Current.ResponseFormatHandlers.Add(new JsonNetFormatHandler { JsonSerializerSettings = CreateJsonSerializerSettings(), Formatting = Formatting.Indented });

            FormatManager.Current.RequestFormatHandlers.Clear();
            FormatManager.Current.RequestFormatHandlers.Add(new XhtmlFormatHandler { IgnoreMissingXslt = true });
            FormatManager.Current.RequestFormatHandlers.Add(new XmlFormatHandler { IgnoreMissingXslt = true });
            FormatManager.Current.RequestFormatHandlers.Add(new JsonNetFormatHandler { JsonSerializerSettings = CreateJsonSerializerSettings(), Formatting = Formatting.Indented });

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }

        protected void Application_Error(object sender, EventArgs e)
        {
            var ex = Server.GetLastError();

            // Hide server errors
            var httpEx = ex as HttpException ?? new HttpException((int)HttpStatusCode.InternalServerError, "There was an internal server error.", ex);

            // Hide routing errors with the assumption that if this has been raised, the controller must exist and the action
            // must exist but that the method is not allowed. The CatchAll route should handle the case where a controller
            // doesn't exist.
            if (httpEx.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                httpEx = new HttpException((int)HttpStatusCode.MethodNotAllowed, "The " + Request.HttpMethod + " verb is not allowed for this resource", ex);
            }

            var routeData = new RouteData();
            routeData.Values.Add("controller", "Error");
            routeData.Values.Add("action", "ErrorDetail");
            routeData.Values.Add("httpException", httpEx);

            Server.ClearError();
            Response.Clear();

            IController errorController = new ErrorController();
            errorController.Execute(new RequestContext(new RomHttpContextWrapper(Context), routeData));
        }

        public static JsonSerializerSettings CreateJsonSerializerSettings()
        {
            var jsonSerializerSettings = new JsonSerializerSettings
            {
                DefaultValueHandling = DefaultValueHandling.Ignore,
                NullValueHandling = NullValueHandling.Ignore
            };

            jsonSerializerSettings.Converters.Add(new IsoDateTimeConverter());
            jsonSerializerSettings.Converters.Add(new StringEnumConverter());

            return jsonSerializerSettings;
        }
    }
}